
#include "uci_base_data.h"

using namespace datasets_uci;

// [*] datasets_uci::CSingleAttributeSettings

datasets_uci::CSingleAttributeSettings::CSingleAttributeSettings()
{
	Clear();
}

datasets_uci::CSingleAttributeSettings::~CSingleAttributeSettings()
{

}

void datasets_uci::CSingleAttributeSettings::Clear()
{
	strName = "NULL";
	InputMode = INPUT_MODE_VALUE;
	OutputMode = OUTPUT_MODE_VALUE;
	fIgnoreLetterCase = true;
	EnumDict.Clear();
	SplitChars = ",. \t\r\n";
	IgnoreChars = " \t\r\n";
}

bool datasets_uci::CSingleAttributeSettings::LoadSettingsFromStream( istream& inStream )
{
	if (!(inStream>>strName>>InputMode>>OutputMode>>fIgnoreLetterCase)) return false;
	if (strName == "#") return false;
	if (InputMode == INPUT_MODE_ENUM)
	{
		EnumDict.Clear();
		char strTemp[10001];
		while (CDataStructureTools::InputFromStream(inStream, strTemp, 10000, SplitChars.c_str(), IgnoreChars.c_str()) > 0)
		{
			if (strcmp(strTemp, "#") == 0) break;
			if (fIgnoreLetterCase)
				CDataStructureTools::ToLowerCase(strTemp);
			EnumDict.GetID(strTemp, true);
		}
		if (EnumDict.Size() == 0) return false;
	}
	return true;
}

void datasets_uci::CSingleAttributeSettings::SaveSettingsToStream( ostream& outStream ) const
{
	outStream<<strName<<"\t"<<InputMode<<"\t"<<OutputMode<<"\t"<<fIgnoreLetterCase<<endl;
	if (InputMode == INPUT_MODE_ENUM)
	{
		int ii = EnumDict.Size();
		int i;
		for ( i = 0; i < ii; ++i )
			outStream<<*EnumDict.GetValue(i)<<", ";
		outStream<<"#"<<endl;
	}
}


int datasets_uci::CSingleAttributeSettings::GetEnumAmount() const
{
	return EnumDict.Size();
}
int datasets_uci::CSingleAttributeSettings::GetOutputDimension() const
{
	switch (OutputMode)
	{
	case OUTPUT_MODE_VALUE:
		return 1;
		break;
	case OUTPUT_MODE_BIT_MAPPING:
		return EnumDict.Size();
		break;
	default:
		break;
	}
	return 0;
}

int datasets_uci::CSingleAttributeSettings::LoadAttributeFromStream( istream& inStream, double* pDstData ) const
{
	string strAttributeValue;
	int InputEnumID;
	double InputValue;
	int ret = ERROR_SUCCESSFUL;
	if (ret==ERROR_SUCCESSFUL && CDataStructureTools::InputFromStream(inStream, strAttributeValue, SplitChars.c_str(), IgnoreChars.c_str()) < 0)
		ret = ERROR_STREAM;
	if (ret==ERROR_SUCCESSFUL && (strAttributeValue=="" || strAttributeValue=="?"))
		ret = ERROR_MISSING;
	if (ret==ERROR_SUCCESSFUL)
	{
		switch (InputMode)
		{
		case INPUT_MODE_VALUE:
			if (sscanf(strAttributeValue.c_str(), "%lf", &InputValue) != 1)
			{
				ret = ERROR_INVALID_VALUE;
				break;
			}
			// Make Output Value
			if (OutputMode == OUTPUT_MODE_VALUE)
				*pDstData = InputValue;
			if (OutputMode == OUTPUT_MODE_BIT_MAPPING)
				*pDstData = InputValue;
			break;
		case INPUT_MODE_ENUM:
			if (fIgnoreLetterCase)
				CDataStructureTools::ToLowerCase(strAttributeValue);
			InputEnumID = EnumDict.GetID_Const(strAttributeValue);
			if (InputEnumID < 0)
			{
				ret = ERROR_INVALID_VALUE;
				break;
			}
			// Make Output Value
			if (OutputMode == OUTPUT_MODE_VALUE)
				*pDstData = InputEnumID;
			if (OutputMode == OUTPUT_MODE_BIT_MAPPING)
			{
				int ii = EnumDict.Size();
				int i;
				for ( i = 0; i < ii; ++i )
					pDstData[i] = 0.0;
				pDstData[InputEnumID] = 1.0;
			}
			break;
		default:
			break;
		}
	}
	if (ret!=ERROR_SUCCESSFUL)
	{
		if (OutputMode == OUTPUT_MODE_VALUE)
			*pDstData = 0.0;
		if (OutputMode == OUTPUT_MODE_BIT_MAPPING)
		{
			int ii = EnumDict.Size();
			int i;
			for ( i = 0; i < ii; ++i )
				pDstData[i] = 0.0;
		}
	}
	return ret;
}

// [*] datasets_uci::CAttributeSetSettings

datasets_uci::CAttributeSetSettings::CAttributeSetSettings()
{
	Clear();
}

datasets_uci::CAttributeSetSettings::~CAttributeSetSettings()
{
}

void datasets_uci::CAttributeSetSettings::Clear()
{
	AttributeAmount = 0;
	PerAttSettings.Clear();
	PerAttFeatureOffset.Clear(); PerAttFeatureOffset.PushBack(0);
	FeatureDimension = 0;

	LabelAttributePosition = 0;
	LabelAttributeSettings.Clear();
}

void datasets_uci::CAttributeSetSettings::SetLabelAttributeSettings(
	int LabelAttributePosition, const CSingleAttributeSettings& SingleAttributeSettings)
{
	this->LabelAttributePosition = LabelAttributePosition;
	this->LabelAttributeSettings = SingleAttributeSettings;
}

void datasets_uci::CAttributeSetSettings::PushBack( const CSingleAttributeSettings& SingleAttributeSettings )
{
	++AttributeAmount;
	PerAttSettings.PushBack(SingleAttributeSettings);
	FeatureDimension += SingleAttributeSettings.GetOutputDimension();
	PerAttFeatureOffset.PushBack(FeatureDimension);
}

void datasets_uci::CAttributeSetSettings::LoadConfigFromFile( string strFN_AttributeSetSettings )
{
	ifstream inFile(strFN_AttributeSetSettings.c_str());

	string strLabelAttributeName;
	CDataStructureTools::InputFromStream(inFile, strLabelAttributeName, ",. \t\r\n", " \t\r\n");

	Clear();
	CSingleAttributeSettings tSingleAttributeSettings;
	while (tSingleAttributeSettings.LoadSettingsFromStream(inFile))
	{
		if (tSingleAttributeSettings.strName == strLabelAttributeName)
			this->SetLabelAttributeSettings(AttributeAmount, tSingleAttributeSettings);
		else
			this->PushBack(tSingleAttributeSettings);
	}
	inFile.close();
	inFile.clear();
}

void datasets_uci::CAttributeSetSettings::ComputeFeatureSettings()
{
	AttributeAmount = (int)PerAttSettings.Size;
	PerAttFeatureOffset.Clear(); PerAttFeatureOffset.PushBack(0);
	FeatureDimension = 0;
	int i;
	for ( i = 0; i < AttributeAmount; ++i )
	{
		FeatureDimension += PerAttSettings.pElement[i].GetOutputDimension();
		PerAttFeatureOffset.PushBack(FeatureDimension);
	}
}

int datasets_uci::CAttributeSetSettings::LoadFeatureFromStream(
	istream& inStream, int& DstLabel, CSimpleTypeArray<double>& DstFeatureList) const
{
	int ret = CSingleAttributeSettings::ERROR_SUCCESSFUL;
	DstFeatureList.Resize(FeatureDimension);
	DstFeatureList.Fill(0.0);
	int i, rvi;
	CSimpleTypeArray<double> zz;
	zz.Resize(LabelAttributeSettings.GetOutputDimension());
	for ( i = 0; i <= AttributeAmount; ++i )
	{
		if (i == LabelAttributePosition)
		{
			rvi = LabelAttributeSettings.LoadAttributeFromStream(
				inStream, zz.pElement);
			if (ret == CSingleAttributeSettings::ERROR_SUCCESSFUL)
				ret = rvi;
			DstLabel = CMyMath::TranslateNumber_Round(zz.pElement[0], (int)0);
		}
		if (i >= AttributeAmount) break;

		rvi = PerAttSettings.pElement[i].LoadAttributeFromStream(
			inStream, DstFeatureList.pElement + PerAttFeatureOffset.pElement[i]);
		if (ret == CSingleAttributeSettings::ERROR_SUCCESSFUL)
			ret = rvi;
		if (rvi == CSingleAttributeSettings::ERROR_STREAM)
			break;
	}
	return ret;
}

// [*] datasets_uci::C_UCI_LabeledDataSet


datasets_uci::C_UCI_LabeledDataSet::C_UCI_LabeledDataSet()
{
	InitAttributeSetSettings(NULL);
}

datasets_uci::C_UCI_LabeledDataSet::~C_UCI_LabeledDataSet()
{
}

void datasets_uci::C_UCI_LabeledDataSet::InitAttributeSetSettings( CAttributeSetSettings* pASS )
{
	this->pASS = pASS;
	FeatureDimension = (pASS==NULL ? 0 : pASS->FeatureDimension);
	this->ClearAndInit(FeatureDimension);
}

void datasets_uci::C_UCI_LabeledDataSet::InitData( string strFN_Data )
{
	this->ClearAndInit(FeatureDimension);
	if (pASS == NULL) return;
	int tLabel, rvi;
	CSimpleTypeArray<double> tFeatureList;
	ifstream inFile(strFN_Data.c_str());
	for ( ; ; )
	{
		if (ExampleAmount == 14)
			ExampleAmount = ExampleAmount;
		rvi = pASS->LoadFeatureFromStream(inFile, tLabel, tFeatureList);
		if (rvi == CSingleAttributeSettings::ERROR_STREAM)
			break;
		if (rvi == CSingleAttributeSettings::ERROR_SUCCESSFUL)
			this->PushBack(tLabel, tFeatureList.pElement);
	}
	inFile.close();
	inFile.clear();
}

